#pragma once
#include <iostream>
#include "util.hpp"
#include "online.hpp"
#include "db.hpp"

/*
    游戏房间模块
    广播reqs到房间所有人
*/

enum room_statu
{
    GAME_START,
    GAME_OVER
};
#define CHESS_WHITE 1
#define CHESS_BLACK 2

#define BOARD_ROW 15
#define BOARD_COL 15

class room
{
private:
    bool five(int dx, int dy, int row, int col, int color)
    {
        int count = 1;
        int search_row = row + dx;
        int search_col = col + dy;
        while ((search_row >= 0 && search_row < BOARD_ROW) &&
               (search_col >= 0 && search_col < BOARD_COL) &&
               (_board[search_row][search_col] == color))
        {
            count++;
            search_row += dx;
            search_col += dy;
        }
        if (count >= 5)
            return true;
        search_row = row - dx;
        search_col = col - dy;
        while ((search_row >= 0 && search_row < BOARD_ROW) &&
               (search_col >= 0 && search_col < BOARD_COL) &&
               (_board[search_row][search_col] == color))
        {
            count++;
            search_row -= dx;
            search_col -= dy;
        }
        return (count >= 5);
    }
    /*
    (0,1) (1,0) (1,1) (1,-1) 五子棋连线胜利的方向向量
     */
    bool check_win(int row, int col, int color)
    {
        return five(0, 1, row, col, color) || five(1, 0, row, col, color) ||
               five(1, 1, row, col, color) || five(1, -1, row, col, color);
    }

public:
    room(uint64_t room_id, user_table *tb_user, online_manager *online_user)
        : _room_id(room_id), _statu(GAME_START), _player_count(0),
          _tb_user(tb_user), _online_user(online_user),
          _board(BOARD_ROW, std::vector<int>(BOARD_COL, 0))
    {
        LOG(INFO, "%lu 房间创建成功!!\n", _room_id);
    }
    ~room()
    {
        LOG(INFO, "%lu 房间关闭成功!!\n", _room_id);
    }

    uint64_t id() { return _room_id; }
    room_statu statu() { return _statu; }
    int player_count() { return _player_count; }
    void add_white_user(uint64_t uid)
    {
        _white_id = uid;
        _player_count++;
    }
    void add_black_user(uint64_t uid)
    {
        _black_id = uid;
        _player_count++;
    }
    uint64_t get_white_user() { return _white_id; }
    uint64_t get_black_user() { return _black_id; }

    Json::Value handle_chess(Json::Value &req)
    {
        Json::Value json_resp = req;
        int chess_row = req["row"].asInt();
        int chess_col = req["col"].asInt();
        uint64_t cur_uid = req["uid"].asUInt64();
        int cur_color = (cur_uid == _white_id ? CHESS_WHITE : CHESS_BLACK);
        if (!_online_user->is_in_game_room(_white_id))
        {
            json_resp["result"] = true;
            json_resp["reason"] = "运气真好！对方掉线，不战而胜！";
            json_resp["winner"] = (Json::UInt64)_black_id;
            return json_resp;
        }

        if (!_online_user->is_in_game_room(_black_id))
        {
            json_resp["result"] = true;
            json_resp["reason"] = "运气真好！对方掉线，不战而胜！";
            json_resp["winner"] = (Json::UInt64)_white_id;
            return json_resp;
        }
        if (_board[chess_row][chess_col] != 0)
        {
            json_resp["result"] = false;
            json_resp["reason"] = "当前位置已经有了其他棋子！";
            return json_resp;
        }
        _board[chess_row][chess_col] = cur_color;
        bool ret = check_win(chess_row, chess_col, cur_color);

        if (ret)
        {
            json_resp["reason"] = "五星连珠";
            json_resp["winner"] = req["uid"];
        }
        else
        {
            json_resp["winner"] = (Json::UInt64)0;
        }

        json_resp["result"] = true;
        return json_resp;
    }

    Json::Value handle_chat(Json::Value &req)
    {
        Json::Value resq = req;
        resq["result"] = true;
        return resq;
    }

    void handle_exit(uint64_t uid)
    {
        // 如果是下棋中退出，则对方胜利，否则下棋结束了退出，则是正常退出
        Json::Value json_resp;
        if (_statu == GAME_START)
        {
            uint64_t winner_id = (Json::UInt64)(uid == _white_id ? _black_id : _white_id);
            json_resp["optype"] = "put_chess";
            json_resp["result"] = true;
            json_resp["reason"] = "对方掉线，不战而胜！";
            json_resp["room_id"] = (Json::UInt64)_room_id;
            json_resp["uid"] = (Json::UInt64)uid;
            json_resp["row"] = -1;
            json_resp["col"] = -1;
            json_resp["winner"] = (Json::UInt64)winner_id;
            uint64_t loser_id = winner_id == _white_id ? _black_id : _white_id;
            _tb_user->win(winner_id);
            _tb_user->lose(loser_id);
            _statu = GAME_OVER;
            broadcast(json_resp);
        }
        // 房间中玩家数量--
        _player_count--;
        return;
    }

    /*总的请求处理函数，在函数内部，区分请求类型，根据不同的请求调用不同的处理函数，得到响应进行广播*/
    void handle_request(Json::Value &req)
    {
        Json::Value json_resp;
        uint64_t room_id = req["room_id"].asUInt64();
        if (room_id != _room_id)
        {
            json_resp["optype"] = req["optype"].asString();
            json_resp["result"] = false;
            json_resp["reason"] = "房间号不匹配！";
            return broadcast(json_resp);
        }

        // 判断请求类型
        if (req["optype"].asString() == "put_chess")
        {
            json_resp = handle_chess(req);
            if (json_resp["winner"].asInt64() != 0)
            {
                uint64_t winid = json_resp["winner"].asInt64();
                uint64_t loseid = winid == _white_id ? _black_id : _white_id;
                _tb_user->win(winid);
                _tb_user->lose(loseid);
                _statu = GAME_OVER;
            }
        }
        else if (req["optype"].asString() == "chat")
        {
            json_resp = handle_chat(req);
        }
        else
        {
            // 未知请求
            json_resp["optype"] = req["optype"].asString();
            json_resp["result"] = false;
            json_resp["reason"] = "未知请求类型";
        }
        broadcast(json_resp);
    }
    void broadcast(Json::Value &resp)
    {
        // 序列化
        std::string body;
        json_util::serialize(resp, body);

        wsserver_t::connection_ptr wconn = _online_user->get_conn_from_room(_white_id);
        if (wconn.get() != nullptr)
        {
            wconn->send(body);
        }
        else
        {
            LOG(DEBUG, "白棋方无连接\n");
        }

        wsserver_t::connection_ptr bconn = _online_user->get_conn_from_room(_black_id);
        if (bconn.get() != nullptr)
        {
            bconn->send(body);
        }
        else
        {
            LOG(DEBUG, "黑棋方无连接\n");
        }

        return;
    }

private:
    // 房间id
    uint64_t _room_id;
    // 房间状态
    room_statu _statu;
    // 玩家数
    int _player_count;
    // 执白子玩家id
    uint64_t _white_id;
    // 执黑子玩家id
    uint64_t _black_id;
    // user 数据库
    user_table *_tb_user;
    // 在线玩家管理
    online_manager *_online_user;
    // 棋盘
    std::vector<std::vector<int>> _board;
};

using room_ptr = std::shared_ptr<room>;

class room_manager
{
public:
    room_manager(user_table *tb_user, online_manager *online_user)
        : _next_rid(1),
          _tb_user(tb_user),
          _online_user(online_user)
    {
    }

    room_ptr create_room(uint64_t uid1, uint64_t uid2)
    {
        if (_online_user->is_in_game_hall(uid1) == false)
        {
            LOG(INFO, "用户：%lu 不在大厅中，创建房间失败!\n", uid1);
            return room_ptr();
        }
        if (_online_user->is_in_game_hall(uid2) == false)
        {
            LOG(INFO, "用户：%lu 不在大厅中，创建房间失败!\n", uid2);
            return room_ptr();
        }
        std::unique_lock<std::mutex> lock(_mutex);
        room_ptr _room_ptr = std::make_shared<room>(_next_rid, _tb_user, _online_user);
        _room_ptr->add_black_user(uid1);
        _room_ptr->add_white_user(uid2);
        _rooms.insert({_next_rid, _room_ptr});
        _users.insert({uid1, _next_rid});
        _users.insert({uid2, _next_rid});
        _next_rid++;
        return _room_ptr;
    }
    /*通过房间ID获取房间信息*/
    room_ptr get_room_by_rid(uint64_t rid)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _rooms.find(rid);
        if (it == _rooms.end())
        {
            return room_ptr();
        }
        return it->second;
    }
    /*通过用户ID获取房间信息*/
    room_ptr get_room_by_uid(uint64_t uid)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        // 1. 通过用户ID获取房间ID
        auto uit = _users.find(uid);
        if (uit == _users.end())
        {
            return room_ptr();
        }
        uint64_t rid = uit->second;
        // 2. 通过房间ID获取房间信息
        auto rit = _rooms.find(rid);
        if (rit == _rooms.end())
        {
            return room_ptr();
        }
        return rit->second;
    }

    void remove_room(uint64_t rid)
    {
        room_ptr _room_ptr = get_room_by_rid(rid);
        if (_room_ptr.get() == nullptr)
        {
            return;
        }

        uint64_t uid1 = _room_ptr->get_black_user();
        uint64_t uid2 = _room_ptr->get_white_user();

        std::unique_lock<std::mutex> lock(_mutex);
        _rooms.erase(rid);
        _users.erase(uid1);
        _users.erase(uid2);
    }

    void remove_user(uint64_t uid)
    {
        //std::unique_lock<std::mutex> lock(_mutex); //死锁了！！！
        room_ptr _room_ptr = get_room_by_uid(uid);

        _room_ptr->handle_exit(uid);

        if (_room_ptr->player_count() == 0)
        {
            remove_room(_room_ptr->id());
        }

        return;
    }

private:
    uint64_t _next_rid;
    std::mutex _mutex;
    // user 数据库
    user_table *_tb_user;
    // 在线玩家管理
    online_manager *_online_user;
    std::unordered_map<uint64_t, room_ptr> _rooms;
    std::unordered_map<uint64_t, uint64_t> _users;
};